home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / pc.c < prev    next >
C/C++ Source or Header  |  1991-08-28  |  21KB  |  945 lines

  1. /* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include <conio.h>
  6. #include <dir.h>
  7. #include <dos.h>
  8. #include <io.h>
  9. #include <sys/stat.h>
  10. #include <string.h>
  11. #include <process.h>
  12. #include <fcntl.h>
  13. #include <alloc.h>
  14. #include <stdarg.h>
  15. #include <bios.h>
  16. #include "global.h"
  17. #include "mbuf.h"
  18. #include "proc.h"
  19. #include "iface.h"
  20. #include "internet.h"
  21. #include "session.h"
  22. #include "socket.h"
  23. #include "smtp.h"
  24. #include "cmdparse.h"
  25. #include "dirutil.h"
  26. #include "pc.h"
  27.  
  28. #define    CTLC    0x3
  29. #define    DEL    0x7f
  30.  
  31. static int kbchar __ARGS((void));
  32. extern int Curdisp;
  33. extern struct proc *Display;
  34. FILE *Rawterm;
  35. unsigned _stklen = 8192;
  36. int Tick;
  37. static int32 Starttime;
  38. int32 Clock;
  39. int Background = 1;
  40.  
  41. int Watchdog = 0;            /* Watch Dog off by default */
  42. int WDTick = 300*(1000 / MSPTICK);    /* 5 minutes watchdog timer */
  43. int WDCurr = 300*(1000 / MSPTICK);    /* Initial count down timer */
  44.  
  45. /* This flag is set by setirq() if IRQ 8-15 is used, indicating
  46.  * that the machine is a PC/AT with a second 8259 interrupt controller.
  47.  * If this flag is set, the interrupt return code in pcgen.asm will
  48.  * send an End of Interrupt command to the second 8259 as well as the
  49.  * first.
  50.  */
  51. int Isat;
  52.  
  53. static char Ttbuf[BUFSIZ];
  54. static char Tsbuf[BUFSIZ];
  55. static int saved_break;
  56.  
  57. /* Keyboard input buffer */
  58. #define    KBSIZE    256
  59. static struct {
  60.     char buf[KBSIZE];
  61.     char *wp;
  62.     char *rp;
  63.     int cnt;
  64. } Keyboard;
  65. int Nokeys = 0;
  66.  
  67. int
  68. am_i_an_AT()
  69. {
  70.     unsigned char *model_code = MK_FP(0xF000,0xFFFE);
  71.  
  72.     if(*model_code == 0xFC)
  73.         return 1;
  74.     else
  75.         return 0;
  76. }
  77. int
  78. errhandler(errval,ax,bp,si)
  79. int errval,ax,bp,si;
  80. {
  81.     return 3;    /* Fail the system call */
  82. }
  83.  
  84. /* Called at startup time to set up console I/O, memory heap */
  85. void
  86. ioinit()
  87. {
  88.  
  89.     /* Fail all I/O errors */
  90.     harderr(errhandler);
  91.  
  92.     /* Save these two file table entries for something more useful */
  93.     fclose(stdaux);
  94.     fclose(stdprn);
  95.     setbuf(stdout,Tsbuf);
  96.  
  97.     Rawterm = fopen("con","wb");
  98.     setbuf(Rawterm,Ttbuf);
  99.     /* this breaks tab expansion so you must use ANSI or NANSI */
  100.     ioctl(fileno(Rawterm), 1, (ioctl(fileno(Rawterm),0) & 0xff) | 0x20);
  101.     saved_break = getcbrk();
  102.     setcbrk(0);
  103.  
  104. #ifdef MSDOS
  105.     /* test to see if we're running on an AT class machine.
  106.      * Set Isat flag accordingly - N1BEE
  107.          */
  108.     Isat = am_i_an_AT();
  109. #endif
  110.     Starttime = bioscnt();
  111.     /* Link timer handler into timer interrupt chain */
  112.     chtimer(btick);
  113.  
  114.     /* Find out what multitasker we're running under, if any */
  115.     chktasker();
  116.  
  117.     /* Initialize keyboard queue */
  118.     Keyboard.rp = Keyboard.wp = Keyboard.buf;
  119.  
  120. }
  121. /* Called just before exiting to restore console state */
  122. void
  123. iostop()
  124. {
  125.     struct iface *ifp,*iftmp;
  126.     void (**fp)();
  127.  
  128.     setbuf(Rawterm,NULLCHAR);
  129.     ioctl(fileno(Rawterm), 1, ioctl(fileno(Rawterm), 0) & 0xff & ~0x20);
  130.     setcbrk(saved_break);
  131.  
  132.     for(ifp = Ifaces;ifp != NULLIF;ifp = iftmp){
  133.         iftmp = ifp->next;
  134.         if_detach(ifp);
  135.     }
  136.     /* Call list of shutdown functions */
  137.     for(fp = Shutdown;*fp != NULLVFP;fp++){
  138.         (**fp)();
  139.     }    
  140. }
  141. /* Spawn subshell */
  142. int
  143. doshell(argc,argv,p)
  144. int argc;
  145. char *argv[];
  146. void *p;
  147. {
  148.     char *command;
  149.     int ret;
  150.  
  151.     if(Background) {
  152.         if(!start_back())
  153.             return -1;
  154.         Nokeys++;
  155.     }
  156.  
  157.     if(argc == 1 || !stricmp(argv[1], "/c")) {
  158.         if((command = getenv("COMSPEC")) == NULLCHAR)
  159.             command = "COMMAND.COM";
  160.         ret = spawnvp(P_WAIT,command,argv);
  161.     } else {
  162.         ret = spawnvp(P_WAIT,argv[1],(argv + 1));
  163.     }
  164.  
  165.     if(Background) {
  166.         Nokeys--;
  167.         stop_back();
  168.     }
  169.  
  170.     return ret;
  171. }
  172.  
  173. /* Spawn mailer as subshell */
  174. int
  175. dobmail(argc,argv,p)
  176. int argc;
  177. char *argv[];
  178. void *p;
  179. {
  180.     char *command;
  181.     int ret;
  182.  
  183.     if(Background) {
  184.         if(!start_back())
  185.             return -1;
  186.         Nokeys++;
  187.     }
  188.  
  189.     if((command = getenv("MAILER")) == NULLCHAR)
  190.         command = "BM.EXE";
  191.     ret = spawnvp(P_WAIT,command,argv);
  192.  
  193.     if(Background) {
  194.         Nokeys--;
  195.         stop_back();
  196.     }
  197.  
  198.     smtptick(NULL);        /* tickle smtp to send any mail */
  199.     return ret;
  200. }
  201.  
  202. /* if multitask mode is set - allow NOS and shell/mail to share system time */
  203. dobackg(argc,argv,p)
  204. int argc;
  205. char *argv[];
  206. void *p;
  207. {
  208.     return setbool(&Background,"Multitasking DOS Shell ",argc,argv);
  209. }
  210.  
  211. /* if watch-dog mode is set - make NOS reboot the system if it stalls */
  212. dowatchdog(argc,argv,p)
  213. int argc;
  214. char *argv[];
  215. void *p;
  216. {
  217.     return setbool(&Watchdog,"NOS Watch Dog",argc,argv);
  218. }
  219.  
  220. /* Keyboard interrupt handler */
  221. void
  222. kbint()
  223. {
  224.     int sig = 0;
  225.     int c;
  226.  
  227.     if(Background && Nokeys)
  228.         return;
  229.     
  230.     while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE){
  231.         sig = 1;
  232.         *Keyboard.wp++ = c;
  233.         if(Keyboard.wp == &Keyboard.buf[KBSIZE])
  234.             Keyboard.wp = Keyboard.buf;
  235.         Keyboard.cnt++;
  236.     }
  237.     if(sig){
  238.         psignal(&Keyboard,0);
  239.     }
  240. }
  241. static int
  242. kbchar()
  243. {
  244.     char i_state;
  245.     char c;
  246.  
  247.     if(Background && Nokeys)
  248.         return -1;
  249.  
  250.     i_state = dirps();
  251.     while(Keyboard.cnt == 0)
  252.         pwait(&Keyboard);
  253.     Keyboard.cnt--;
  254.     restore(i_state);
  255.     c = *Keyboard.rp++;
  256.     if(Keyboard.rp == &Keyboard.buf[KBSIZE])
  257.         Keyboard.rp = Keyboard.buf;
  258.     return uchar(c);
  259. }
  260. /* Flush the raw terminal output */
  261. void
  262. rflush()
  263. {
  264.     fflush(Rawterm);
  265. }
  266.  
  267. #ifdef MSDOS
  268. struct funcstr {
  269.     char fkey;
  270.     char alloced;
  271.     char *fvalue;
  272. };
  273.  
  274. struct funcstr fkeys[] = {
  275.     15,0,NULLCHAR,    /* tab + shift */
  276.     59,1,"\033OP",    /* F1 */
  277.     60,1,"\033OQ",    /* F2 */
  278.     61,1,"\033OR",    /* F3 */
  279.     62,1,"\033OS",    /* F4 */
  280.     63,0,NULLCHAR,    /* F5 */
  281.     64,0,NULLCHAR,    /* F6 */
  282.     65,0,NULLCHAR,    /* F7 */
  283.     66,0,NULLCHAR,    /* F8 */
  284.     67,0,NULLCHAR,    /* F9 */
  285.     68,0,NULLCHAR,    /* F10 */
  286.     71,1,"\010",        /* home*/
  287.     72,1,"\033[A",    /* up arrow*/
  288.     73,1,"\025",        /* pgup */
  289.     75,1,"\033[D",    /* left arrow */
  290.     77,1,"\033[C",    /* right arrow */
  291.     79,1,"\005",        /* end */
  292.     80,1,"\033[B",    /* down arrow */
  293.     81,1,"\012",        /* pgdn */
  294.     82,1,"\001",        /* ins */
  295.     83,1,"\0177",        /* del */
  296.     84,0,NULLCHAR,    /* F1 + shift*/
  297.     85,0,NULLCHAR,    /* F2 + shift*/
  298.     86,0,NULLCHAR,    /* F3 + shift*/
  299.     87,0,NULLCHAR,    /* F4 + shift*/
  300.     88,0,NULLCHAR,    /* F5 + shift*/
  301.     89,0,NULLCHAR,    /* F6 + shift*/
  302.     90,0,NULLCHAR,    /* F7 + shift*/
  303.     91,0,NULLCHAR,    /* F8 + shift*/
  304.     92,0,NULLCHAR,    /* F9 + shift*/
  305.     93,0,NULLCHAR,    /* F10 + shift*/
  306.     94,0,NULLCHAR,    /* F1 + control*/
  307.     95,0,NULLCHAR,    /* F2 + control*/
  308.     96,0,NULLCHAR,    /* F3 + control*/
  309.     97,0,NULLCHAR,    /* F4 + control*/
  310.     98,0,NULLCHAR,    /* F5 + control*/
  311.     99,0,NULLCHAR,    /* F6 + control*/
  312.     100,0,NULLCHAR,    /* F7 + control*/
  313.     101,0,NULLCHAR,    /* F8 + control*/
  314.     102,0,NULLCHAR,    /* F9 + control*/
  315.     103,0,NULLCHAR,    /* F10 + control*/
  316.     104,0,NULLCHAR,    /* F1 + alt*/
  317.     105,0,NULLCHAR,    /* F2 + alt*/
  318.     106,0,NULLCHAR,    /* F3 + alt*/
  319.     107,0,NULLCHAR,    /* F4 + alt*/
  320.     108,0,NULLCHAR,    /* F5 + alt*/
  321.     109,0,NULLCHAR,    /* F6 + alt*/
  322.     110,0,NULLCHAR,    /* F7 + alt*/
  323.     111,0,NULLCHAR,    /* F8 + alt*/
  324.     112,0,NULLCHAR,    /* F9 + alt*/
  325.     113,0,NULLCHAR,    /* F10 + alt*/
  326.     114,0,NULLCHAR,    /* PrtSc + ctl*/
  327.     117,0,NULLCHAR,    /* end  + ctl */
  328.     118,0,NULLCHAR,    /* pgup + ctl */
  329.     119,0,NULLCHAR,    /* home + ctl */
  330.     132,0,NULLCHAR,    /* pgdn + ctl */
  331.       0,0,NULLCHAR
  332. };
  333.  
  334. char Leftover = 0;
  335. char *Nextkey;
  336. #endif
  337.  
  338. /* Read characters from the keyboard, translating them to "real" ASCII.
  339.  * If none are ready, block. The F-10 key is special; translate it to -2.
  340.  */
  341. int
  342. kbread()
  343. {
  344. #ifndef    MSDOS
  345.     int c;
  346. #else
  347.     int c,i,j;
  348.  
  349.     if((c = Leftover) != 0)  {
  350.         Leftover = *Nextkey++;
  351.         return c;
  352.     }
  353. #endif    MSDOS
  354.     if((c = kbchar()) == 0){
  355.         /* Lead-in to a special char */
  356.         c = kbchar();
  357.         switch(c){
  358.         case 3:        /* NULL (bizzare!) */
  359.             c = 0;
  360.             break;
  361.         case 68:    /* F-10 key (used as command-mode escape) */
  362.             if(fkeys[10].fvalue == NULLCHAR){
  363.                 c = -2;
  364.                 break;
  365.             }
  366.         default:    /* Dunno what it is */
  367. #ifdef    MSDOS
  368.             for(i=0;(j = fkeys[i].fkey) != 0;i++)
  369.                 if(j == c) {
  370.                     Nextkey = fkeys[i].fvalue;
  371.                     if(Nextkey == NULLCHAR) {
  372.                         c = -1;
  373.                         return c;
  374.                     }
  375.                     if((c = *Nextkey++) != 0)
  376.                         Leftover = *Nextkey++;
  377.                     else
  378.                         c = -1;
  379.                     return c;
  380.                 }
  381. #endif
  382.             c = -1;
  383.         }
  384.     }
  385.     return c;
  386. }
  387. #ifdef    MSDOS
  388. int
  389. dofkey(argc,argv,p)
  390. int argc;
  391. char *argv[];
  392. void *p;
  393. {
  394.     int c,i,j;
  395.     char *q, *r;
  396.     char str[100];
  397.  
  398.     if(argc == 1) {
  399.        tprintf("key num    key  num    key  num    key  num   key   num\n");
  400.        tprintf("f1   59    sf1   84    cf1   94    af1  104   pgup   73\n");
  401.        tprintf("f2   60    sf2   85    cf2   95    af2  105   pgdn   81\n");
  402.        tprintf("f3   61    sf3   86    cf3   96    af3  106   home   71\n");
  403.        tprintf("f4   62    sf4   87    cf4   97    af4  107   end    79\n");
  404.        tprintf("f5   63    sf5   88    cf5   98    af5  108   arup   72\n");
  405.        tprintf("f6   64    sf6   89    cf6   99    af6  109   ardn   80\n");
  406.        tprintf("f7   65    sf7   90    cf7  100    af7  110   ar l   75\n");
  407.        tprintf("f8   66    sf8   91    cf8  101    af8  111   ar r   77\n");
  408.        tprintf("f9   67    sf9   92    cf9  102    af9  112   ins    82\n");
  409.        tprintf("f10  68    sf10  93    cf10 103    af10 113   del    83\n");
  410.        tprintf("usage: fkey <key number> [<value> | \"string\"]\n");
  411.        return 0;
  412.     }
  413.  
  414.     c = atoi(argv[1]);
  415.     if(c == 0 || c > 255) {
  416.         tprintf("fkey number out of range.\n");
  417.         return 1;
  418.     }
  419.  
  420.     for(j = 0;(i = fkeys[j].fkey) != 0; j++)
  421.         if(i == c) 
  422.             break;
  423.  
  424.     if(i == 0){
  425.         tprintf("fkey number not found\n");
  426.         return 1;
  427.     }
  428.  
  429.     if(argc == 2) {
  430.         q = fkeys[j].fvalue;
  431.         r = str;
  432.         if(q == NULLCHAR)
  433.             tprintf("fkey %d has no assigned value.\n",c);
  434.         else {
  435.             while(*q)
  436.                 if(*q < ' ') { /* This is ASCII dependent !! */
  437.                     *r++ = '^';
  438.                     *r++ = *q++ + 0x40;
  439.                 } else
  440.                     *r++ = *q++;
  441.             *r = '\0';
  442.             tprintf("fkey = %s\n",str);
  443.         }
  444.         return 0;
  445.     }
  446.  
  447.     if(argc == 3) {
  448.         if(fkeys[j].alloced)
  449.             fkeys[j].alloced = 0;
  450.         else
  451.             if(fkeys[j].fvalue != NULLCHAR)
  452.                 free(fkeys[j].fvalue);
  453.  
  454.         r = str;
  455.         q = argv[2];
  456.         while(*q){
  457.             if(*q == '^'){    /* ^ gives control char next */
  458.                 q++;
  459.                 if(*q == '^') {
  460.                     *r++ = *q++; /* No, he wants a ^ */
  461.                 } else {
  462.                     *r++ = *q++ & 0x1f;
  463.                 }
  464.             } else
  465.                 *r++ = *q++;
  466.         }
  467.         *r = '\0';
  468.         fkeys[j].fvalue = strdup(str);
  469.     }
  470.     return 0;
  471. }
  472. #endif
  473.  
  474. /* Install hardware interrupt handler.
  475.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  476.  * Note that bus line IRQ2 maps to IRQ9 on the AT
  477.  */
  478. int
  479. setirq(irq,handler)
  480. unsigned irq;
  481. INTERRUPT (*handler)();
  482. {
  483.     /* Set interrupt vector */
  484.     if(irq < 8){
  485.         setvect(8+irq,handler);
  486.     } else if(irq < 16){
  487.         Isat = 1;
  488.         setvect(0x70 + irq - 8,handler);
  489.     } else {
  490.         return -1;
  491.     }
  492.     return 0;
  493. }
  494. /* Return pointer to hardware interrupt handler.
  495.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  496.  */
  497. INTERRUPT
  498. (*getirq(irq))()
  499. unsigned int irq;
  500. {
  501.     /* Set interrupt vector */
  502.     if(irq < 8){
  503.         return getvect(8+irq);
  504.     } else if(irq < 16){
  505.         return getvect(0x70 + irq - 8);
  506.     } else {
  507.         return NULLVIFP;
  508.     }
  509. }
  510. /* Disable hardware interrupt */
  511. int
  512. maskoff(irq)
  513. unsigned irq;
  514. {
  515.     if(irq < 8){
  516.         setbit(0x21,(char)(1<<irq));
  517.     } else if(irq < 16){
  518.         irq -= 8;
  519.         setbit(0xa1,(char)(1<<irq));
  520.     } else {
  521.         return -1;
  522.     }
  523.     return 0;
  524. }
  525. /* Enable hardware interrupt */
  526. int
  527. maskon(irq)
  528. unsigned irq;
  529.  {
  530.     if(irq < 8){
  531.         clrbit(0x21,(char)(1<<irq));
  532.     } else if(irq < 16){
  533.         irq -= 8;
  534.         clrbit(0xa1,(char)(1<<irq));
  535.     } else {
  536.         return -1;
  537.     }
  538.     return 0;
  539. }
  540. /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
  541. int
  542. getmask(irq)
  543. unsigned irq;
  544. {
  545.     if(irq < 8)
  546.         return (inportb(0x21) & (1 << irq)) ? 0 : 1;
  547.     else if(irq < 16){
  548.         irq -= 8;
  549.         return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
  550.     } else
  551.         return -1;
  552. }
  553. /* Called from assembler stub linked to BIOS interrupt 1C, called on each
  554.  * hardware clock tick. Signal a clock tick to the timer process.
  555.  */
  556. void
  557. ctick()
  558. {
  559.     if(Watchdog)
  560.         if(WDCurr-- == 0)
  561.             sysreset();    
  562.     Tick++;
  563. #ifdef notdef
  564.     Clock++;    /* Keep system time */
  565. #endif
  566.     psignal(&Tick,1);
  567. }
  568. /* Called from the timer process on every tick. NOTE! This function
  569.  * can NOT be called at interrupt time because it calls the BIOS
  570.  */
  571. void
  572. pctick()
  573. {
  574.     long t;
  575.     static long oldt;    /* Value of bioscnt() on last call */
  576.     static long days;    /* # of times bioscnt() has rolled over */
  577.  
  578.     /* Update the time-since-boot */
  579.     t = bioscnt();
  580.  
  581.     if(t < oldt)
  582.         days++;    /* bioscnt has rolled past midnight */
  583.     oldt = t;
  584.     Clock = (days * 0x1800b0) + t - Starttime;
  585. }
  586.  
  587. /* Set bit(s) in I/O port */
  588. void
  589. setbit(port,bits)
  590. unsigned port;
  591. char bits;
  592. {
  593.     outportb(port,(char)inportb(port)|bits);
  594. }
  595. /* Clear bit(s) in I/O port */
  596. void
  597. clrbit(port,bits)
  598. unsigned port;
  599. char bits;
  600. {
  601.     outportb(port,(char)(inportb(port) & ~bits));
  602. }
  603. /* Set or clear selected bit(s) in I/O port */
  604. void
  605. writebit(port,mask,val)
  606. unsigned port;
  607. char mask;
  608. int val;
  609. {
  610.     register char x;
  611.  
  612.     x = inportb(port);
  613.     if(val)
  614.         x |= mask;
  615.     else
  616.         x &= ~mask;
  617.     outportb(port,x);
  618. }
  619. /* Convert a pointer to a long integer */
  620. long
  621. ptol(p)
  622. void *p;
  623. {
  624.     long x;
  625.  
  626.     x = FP_OFF(p);
  627. #ifdef    LARGEDATA
  628.     x |= (long)FP_SEG(p) << 16;
  629. #endif
  630.     return x;
  631. }
  632. void *
  633. ltop(l)
  634. long l;
  635. {
  636.     register unsigned seg,offset;
  637.  
  638.     seg = l >> 16;
  639.     offset = l;
  640.     return MK_FP(seg,offset);
  641. }
  642. #ifdef notdef    /* Assembler versions in pcgen.asm */
  643. /* Multiply a 16-bit multiplier by an arbitrary length multiplicand.
  644.  * Product is left in place of the multiplicand, and the carry is
  645.  * returned
  646.  */
  647. int16
  648. longmul(multiplier,n,multiplicand)
  649. int16 multiplier;
  650. int n;                /* Number of words in multiplicand[] */
  651. register int16 *multiplicand;    /* High word is in multiplicand[0] */
  652. {
  653.     register int i;
  654.     unsigned long pc;
  655.     int16 carry;
  656.  
  657.     carry = 0;
  658.     multiplicand += n;
  659.     for(i=n;i != 0;i--){
  660.         multiplicand--;
  661.         pc = carry + (unsigned long)multiplier * *multiplicand;
  662.         *multiplicand = pc;
  663.         carry = pc >> 16;
  664.         }
  665.     }
  666.     return carry;
  667. }
  668. /* Divide a 16-bit divisor into an arbitrary length dividend using
  669.  * long division. The quotient is returned in place of the dividend,
  670.  * and the function returns the remainder.
  671.  */
  672. int16
  673. longdiv(divisor,n,dividend)
  674. int16 divisor;
  675. int n;                /* Number of words in dividend[] */
  676. register int16 *dividend;    /* High word is in dividend[0] */
  677. {
  678.     /* Before each division, remquot contains the 32-bit dividend for this
  679.      * step, consisting of the 16-bit remainder from the previous division
  680.      * in the high word plus the current 16-bit dividend word in the low
  681.      * word.
  682.      *
  683.      * Immediately after the division, remquot contains the quotient
  684.      * in the low word and the remainder in the high word (which is
  685.      * exactly where we need it for the next division).
  686.      */
  687.     unsigned long remquot;
  688.     register int i;
  689.  
  690.     if(divisor == 0)
  691.         return 0;    /* Avoid divide-by-zero crash */
  692.     remquot = 0;
  693.     for(i=0;i<n;i++,dividend++){
  694.         remquot |= *dividend;
  695.         if(remquot == 0)
  696.             continue;    /* Avoid unnecessary division */
  697. #ifdef    __TURBOC__
  698.         /* Use assembly lang routine that returns both quotient
  699.          * and remainder, avoiding a second costly division
  700.          */
  701.         remquot = divrem(remquot,divisor);
  702.         *dividend = remquot;    /* Extract quotient in low word */
  703.         remquot &= ~0xffffL;    /* ... and mask it off */
  704. #else
  705.         *dividend = remquot / divisor;
  706.         remquot = (remquot % divisor) << 16;
  707. #endif
  708.     }
  709.     return remquot >> 16;
  710. }
  711. #endif
  712. void
  713. sysreset()
  714. {
  715.     void (*foo) __ARGS((void));
  716.  
  717.     foo = MK_FP(0xffff,0);    /* FFFF:0000 is hardware reset vector */
  718.     (*foo)();
  719. }
  720. void
  721. newscreen(sp)
  722. struct session *sp;
  723. {
  724.     if(sp != NULLSESSION)
  725.         sp->screen = callocw(1,sizeof(struct screen));
  726. }
  727. void
  728. freescreen(sp)
  729. struct session *sp;
  730. {
  731.     if(sp == NULLSESSION || sp->screen == NULLSCREEN)
  732.         return;
  733.     if(sp->screen->save != NULLCHAR)
  734.         free(sp->screen->save);
  735.     free((char *)sp->screen);
  736. }
  737.  
  738. /* Save specified session screen and resume console screen */
  739. void
  740. swapscreen(old,new)
  741. struct session *old,*new;
  742. {
  743.     struct text_info tr;
  744.  
  745.     if(old == new)
  746.         return;    /* Nothing to do */
  747.  
  748.     fflush(Rawterm);
  749.     gettextinfo(&tr);
  750.     if(old != NULLSESSION){
  751.         /* Save old screen */
  752.         if(old->screen->save == NULLCHAR)
  753.             old->screen->save
  754.              = malloc(2*tr.screenheight*tr.screenwidth);
  755.         if(old->screen->save != NULLCHAR){
  756.             if(old->split){
  757.                 window(1,1,80,25);
  758.                 tr.winbottom = 25;
  759.             }
  760.             gettext(tr.winleft,tr.wintop,tr.winright,
  761.              tr.winbottom,old->screen->save);
  762.         }
  763.         old->screen->row = tr.cury;
  764.         old->screen->col = tr.curx;
  765.     }
  766.     if(new != NULLSESSION){
  767.         /* Load new screen */
  768.         if(new->screen->save != NULLCHAR){
  769.             if(new->split){
  770.                 window(1,1,80,23);
  771.                 clrscr();
  772.             } else {
  773.                 window(1,1,80,25);
  774.                 clrscr();
  775.             }
  776.             puttext(tr.winleft,tr.wintop,tr.winright,
  777.              tr.winbottom,new->screen->save);
  778.             gotoxy(new->screen->col,new->screen->row);
  779.             /* Free the memory (saves 4K on a continuous basis) */
  780.             free(new->screen->save);
  781.             new->screen->save = NULLCHAR;
  782.         } else {
  783.             clrscr();    /* Start with a fresh slate */
  784.             if(new->split){
  785.                 new->tsavex = 1;
  786.                 new->tsavey = 1;
  787.                 new->bsavex = 1;
  788.                 new->bsavey = 24;
  789.                 window(1,1,80,25);
  790.                 cputs("_\b");
  791.                 window(1,1,80,23);
  792.             }
  793.         }
  794.     }
  795.     alert(Display,1);    /* Wake him up */
  796. }
  797. void
  798. display(i,v1,v2)
  799. int i;
  800. void *v1;
  801. void *v2;
  802. {
  803.     int c;
  804.     struct session *sp;
  805.  
  806.     /* This is very tricky code. Because the value of "Current" can
  807.      * change any time we do a pwait, we have to be careful to detect
  808.      * any change and go back and start again.
  809.      */
  810.     for(;;){
  811.         sp = Current;
  812.  
  813.         if(sp->morewait){
  814.             pwait(&sp->row);
  815.             if(sp != Current || sp->row <= 0){
  816.                 /* Current changed value, or the user
  817.                  * hasn't really hit a key
  818.                  */
  819.                 continue;
  820.             }
  821.             /* Erase the prompt */
  822.             fprintf(Rawterm,"\r        \r");
  823.         }
  824.         sp->morewait = 0;
  825.         if((c = rrecvchar(sp->output)) == -1){
  826.             /* the alert() in swapscreen will cause this to
  827.              * return -1 when current changes
  828.              */
  829.             pwait(NULL);    /* Prevent a nasty loop */
  830.             continue;
  831.         }
  832.         if(sp->split){
  833.             if(c == 0x0a){
  834.                 cputs(Eol);
  835.                 clreol();
  836.             } else
  837.                 putch(c);
  838.         } else {
  839.             putc(c,Rawterm);
  840.         }
  841.         if(sp->record != NULLFILE)
  842.             putc(c,sp->record);
  843.         if(sp->flowmode && c == '\n' && --sp->row <= 0){
  844.             fprintf(Rawterm,"--More--");
  845.             sp->morewait = 1;
  846.         }
  847.     }
  848. }
  849. /* Return time since startup in milliseconds. If the system has an
  850.  * 8254 clock chip (standard on ATs and up) then resolution is improved
  851.  * below 55 ms (the clock tick interval) by reading back the instantaneous
  852.  * value of the counter and combining it with the global clock tick counter.
  853.  * Otherwise 55 ms resolution is provided.
  854.  *
  855.  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
  856.  * between the two reads. The tick counter is examined before and after the
  857.  * hardware counter is read. If the tick counter changes, try again.
  858.  * Note: the hardware counter counts down from 65536.
  859.  */
  860. int32
  861. msclock()
  862. {
  863.     int32 hi;
  864.     int16 lo;
  865.     int16 count[4]; /* extended (48-bit) counter of timer clocks */
  866.  
  867.     if(!Isat)
  868.         return Clock * MSPTICK;
  869.  
  870.     do {
  871.         hi = Clock + Tick;
  872.         lo = clockbits();
  873.     } while(hi != Clock + Tick); /* Make sure a tick didn't just occur */
  874.  
  875.     count[0] = 0;
  876.     count[1] = hi >> 16;
  877.     count[2] = hi;
  878.     count[3] = -lo;
  879.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  880.     longdiv(13125,4,count);
  881.     return ((long)count[2] << 16) + count[3];
  882. }
  883. /* Return clock in seconds */
  884. int32
  885. secclock()
  886. {
  887.     int32 hi;
  888.     int16 lo;
  889.     int16 count[4];    /* extended (48-bit) counter of timer clocks */
  890.  
  891.     if(!Isat)
  892.         return Clock * MSPTICK / 1000L;
  893.  
  894.     do {
  895.         hi = Clock + Tick;
  896.         lo = clockbits();
  897.     } while(hi != Clock + Tick); /* Make sure a tick didn't just occur */
  898.  
  899.     count[0] = 0;
  900.     count[1] = hi >> 16;
  901.     count[2] = hi;
  902.     count[3] = -lo;
  903.     longmul(11,4,count);    /* The ratio 11/13125 is exact */
  904.     longdiv(13125,4,count);
  905.     longdiv(1000,4,count);
  906.     return ((long)count[2] << 16) + count[3];
  907. }
  908.  
  909. int
  910. doisat(argc,argv,p)
  911. int argc;
  912. char *argv[];
  913. void *p;
  914. {
  915.     return setbool(&Isat,"AT/386 mode",argc,argv);
  916. }
  917.  
  918. /* Directly read BIOS count of time ticks. This is used instead of
  919.  * calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
  920.  * wich resets the midnight overflow flag, losing days on the clock.
  921.  */
  922. long
  923. bioscnt()
  924. {
  925.     int i_state;
  926.     long rval;
  927.  
  928.     i_state = dirps();
  929.     rval = * (long far *)MK_FP(0x40,0x6c);
  930.     restore(i_state);
  931.     return rval;
  932. }
  933.  
  934. /* same as getenv(), but return "" instead of NULL when it does not exist */
  935. char *getnenv (name)
  936. char *name;
  937. {
  938.     char *rv;
  939.  
  940.     if ((rv = getenv(name)) == NULL)
  941.          rv = "";            /* NULL replaced by "" */
  942.  
  943.     return rv;
  944. }
  945.